package org.example.compare.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.example.compare.dto.WorkTimeDto;

import java.io.File;
import java.io.IOException;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 测试数据生成器类，用于生成sameDayLeftSeconds函数的测试数据
 */
public class SameDayLeftSecondsTestDataGenerator {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 生成不重叠的时间段
     *
     * @param random   随机数生成器
     * @param minSlots 最小时间段数
     * @param maxSlots 最大时间段数
     * @return 不重叠的时间段列表
     */
    private static List<WorkTimeDto> generateNonOverlappingTimeSlots(Random random, int minSlots, int maxSlots) {
        List<WorkTimeDto> workTimes = new ArrayList<>();

        // 随机生成时间段数量
        int slotCount = minSlots + random.nextInt(maxSlots - minSlots + 1);

        // 生成不重叠的时间段
        List<int[]> timeSlots = new ArrayList<>();
        int currentTime = 0 * 60; // 起始时间0:00(以分钟为单位)
        int endTime = 24 * 60;    // 结束时间24:00(以分钟为单位)

        for (int i = 0; i < slotCount && currentTime < endTime - 30; i++) { // 确保至少有30分钟生成时间段
            // 计算剩余可分配时间
            int remainingTime = endTime - currentTime;
            int remainingSlots = slotCount - i;

            // 确保不会出现负数或零的情况
            if (remainingSlots <= 0 || remainingTime <= 0) {
                break;
            }

            // 生成起始时间(在当前时间和结束时间之间)
            int maxInterval = Math.max(1, remainingTime / remainingSlots);
            int startMinute = currentTime + random.nextInt(maxInterval);

            // 确保不会超出结束时间
            if (startMinute >= endTime) {
                break;
            }

            // 生成持续时间(30分钟到4小时，但不超过剩余时间)
            int maxDuration = Math.min(210, endTime - startMinute - 1);
            if (maxDuration < 30) { // 如果剩余时间不足30分钟，跳过
                break;
            }
            int duration = 30 + random.nextInt(maxDuration - 30 + 1);
            int endMinute = startMinute + duration;

            // 确保结束时间不超过限制
            if (endMinute > endTime) {
                endMinute = endTime;
            }

            // 如果时间段有效，则添加
            if (endMinute > startMinute) {
                timeSlots.add(new int[]{startMinute, endMinute});
                // 更新当前时间，确保下一个时间段不会重叠
                currentTime = endMinute + 10 + random.nextInt(30); // 至少间隔10分钟，最多40分钟
            } else {
                break;
            }
        }

        // 创建WorkTimeDto对象
        for (int[] slot : timeSlots) {
            int startHour = slot[0] / 60;
            int startMinute = slot[0] % 60;
            int endHour = slot[1] / 60;
            int endMinute = slot[1] % 60;

            WorkTimeDto workTimeDto = new WorkTimeDto();
            workTimeDto.update(
                    new java.sql.Time(startHour, startMinute, 0),
                    new java.sql.Time(endHour, endMinute, 0)
            );
            workTimes.add(workTimeDto);
        }

        return workTimes;
    }

    /**
     * 生成随机时间
     *
     * @param random 随机数生成器
     * @return 随机时间
     */
    private static Time generateRandomTime(Random random) {
        int hour = random.nextInt(24);
        int minute = random.nextInt(60);
        int second = random.nextInt(60);
        return new Time(hour, minute, second);
    }

    /**
     * 生成随机测试数据并保存到文件
     */
    public static void generateRandomTestData(int iteration) throws IOException {
        String basePath = "../../test_data/sameDayLeftSeconds/random_case_" + iteration;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        Random random = new Random();

        // 生成日期到工作时间的映射(1-5个日期)
        Map<String, List<WorkTimeDto>> dateToWorkTimeMap = new HashMap<>();
        int dateCount = 1 + random.nextInt(5);

        Date targetDate = null;

        for (int i = 0; i < dateCount; i++) {
            // 生成日期(2025年内的随机日期)
            Calendar cal = Calendar.getInstance();
            cal.set(2025, random.nextInt(12), 1 + random.nextInt(28), 0, 0, 0);
            cal.set(Calendar.MILLISECOND, 0);
            Date date = cal.getTime();

            // 为该日期生成1-3个工作时间段
            List<WorkTimeDto> workTimeDtos = generateNonOverlappingTimeSlots(random, 1, 3);

            dateToWorkTimeMap.put(new SimpleDateFormat("yyyy-MM-dd").format(date), workTimeDtos);

            // 随机选择一个作为目标日期
            if (targetDate == null || random.nextInt(3) == 0) {
                targetDate = date;
            }
        }

        // 目标日期始终在映射中（移除了10%概率不在映射中的逻辑）
        Time curTime = generateRandomTime(random);
        Time finalTime = generateRandomTime(random);

        // 确保最终时间不早于当前时间
        if (finalTime.before(curTime)) {
            // 交换时间
            Time temp = curTime;
            curTime = finalTime;
            finalTime = temp;
        }

        // 保存所有测试数据到一个JSON文件中
        Map<String, Object> testData = new HashMap<>();
        testData.put("rDate", targetDate);
        testData.put("rCurTime", curTime.toString());
        testData.put("rFinalTime", finalTime.toString());
        testData.put("rDateToWorkTime", dateToWorkTimeMap);

        objectMapper.writeValue(new File(basePath + "/test_cases.json"), testData);
    }

    /**
     * 生成手动测试案例数据并保存到文件
     */
    public static void generateManualTestData(int caseNumber) throws IOException {
        String basePath = "../../test_data/sameDayLeftSeconds/manual_case_" + caseNumber;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        Date date;
        Time curTime;
        Time finalTime;
        List<WorkTimeDto> workTimeDtos = new ArrayList<>();
        Map<String, List<WorkTimeDto>> dateToWorkTimeMap = new HashMap<>();

        if (caseNumber == 1) {
            // 案例1: 目标日期不在映射中
            Calendar cal = Calendar.getInstance();
            cal.set(2025, Calendar.JANUARY, 1, 0, 0, 0);
            cal.set(Calendar.MILLISECOND, 0);
            date = cal.getTime();

            // 生成一个在映射中的日期（但不是目标日期）
            Calendar mappedCal = Calendar.getInstance();
            mappedCal.set(2025, Calendar.JANUARY, 2, 0, 0, 0);
            mappedCal.set(Calendar.MILLISECOND, 0);
            Date mappedDate = mappedCal.getTime();

            WorkTimeDto workTime1 = new WorkTimeDto();
            workTime1.update(new Time(9, 0, 0), new Time(12, 0, 0));
            workTimeDtos.add(workTime1);

            WorkTimeDto workTime2 = new WorkTimeDto();
            workTime2.update(new Time(13, 0, 0), new Time(18, 0, 0));
            workTimeDtos.add(workTime2);

            // 将工作时间段映射到另一个日期
            dateToWorkTimeMap.put(new SimpleDateFormat("yyyy-MM-dd").format(mappedDate), workTimeDtos);

            // 目标日期设置为不在映射中的日期
            curTime = new Time(10, 30, 0);
            finalTime = new Time(15, 30, 0);
        } else if (caseNumber == 2) {
            // 案例2: 当前时间晚于最终时间
            Calendar cal = Calendar.getInstance();
            cal.set(2025, Calendar.JANUARY, 2, 0, 0, 0);
            cal.set(Calendar.MILLISECOND, 0);
            date = cal.getTime();

            WorkTimeDto workTime1 = new WorkTimeDto();
            workTime1.update(new Time(8, 0, 0), new Time(12, 0, 0));
            workTimeDtos.add(workTime1);

            WorkTimeDto workTime2 = new WorkTimeDto();
            workTime2.update(new Time(13, 0, 0), new Time(17, 0, 0));
            workTimeDtos.add(workTime2);

            // 设置当前时间晚于最终时间
            curTime = new Time(16, 30, 0);  // 当前时间16:30
            finalTime = new Time(14, 30, 0); // 最终时间14:30（更早）

            // 将工作时间映射保存为日期字符串到工作时间列表的映射
            dateToWorkTimeMap.put(new SimpleDateFormat("yyyy-MM-dd").format(date), workTimeDtos);
        } else {
            throw new IllegalArgumentException("不支持的手动案例编号: " + caseNumber);
        }

        // 保存所有测试数据到一个JSON文件中
        Map<String, Object> testData = new HashMap<>();
        testData.put("rDate", date);
        testData.put("rCurTime", curTime.toString());
        testData.put("rFinalTime", finalTime.toString());
        testData.put("rDateToWorkTime", dateToWorkTimeMap);

        objectMapper.writeValue(new File(basePath + "/test_cases.json"), testData);
    }

    public static void main(String[] args) {
        try {
            // 确保主目录存在
            File mainDir = new File("../../test_data/sameDayLeftSeconds");
            if (!mainDir.exists()) {
                mainDir.mkdirs();
            }

            // 生成50组随机测试数据
            for (int i = 1; i <= 50; i++) {
                // 检查是否存在以random_case_i命名的文件夹，没有则创建
                String casePath = "../../test_data/sameDayLeftSeconds/random_case_" + i;
                File caseDir = new File(casePath);
                if (!caseDir.exists()) {
                    caseDir.mkdirs();
                }

                generateRandomTestData(i);
                System.out.println("测试数据集 " + i + " 已成功生成并保存到 " + casePath);
            }

            // 生成2个手动测试案例
            for (int i = 1; i <= 2; i++) {
                generateManualTestData(i);
                String casePath = "../../test_data/sameDayLeftSeconds/manual_case_" + i;
                System.out.println("手动测试案例 " + i + " 已成功生成并保存到 " + casePath);
            }

            System.out.println("所有测试数据已成功生成并保存到../../test_data/sameDayLeftSeconds目录下");
        } catch (IOException e) {
            System.err.println("生成测试数据时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
